<template>
  <div class="goods-sku">
    <dl v-for="item in specs" :key="item.name">
      <dt>{{ item.name }}</dt>
      <dd>
        <template v-for="value in item.values" :key="value.name">
          <img
            @click="updateSelect(value, item)"
            v-if="value.picture"
            :class="{ selected: value.select, disabled: value.disabled }"
            :src="value.picture"
            alt=""
          />
          <span
            :class="{ selected: value.select, disabled: value.disabled }"
            @click="updateSelect(value, item)"
            v-else
            >{{ value.name }}</span
          >
        </template>
      </dd>
    </dl>
  </div>
</template>
<script>
import bwPowerSet from "@/vendor/power-set";
export default {
  name: "GoodsSku",
  props: {
    specs: {
      type: Array,
      default: () => [],
    },
    skuId: {
      type: String,
      default: "",
    },
    skus: {
      type: Array,
      default: () => [],
    },
  },
  setup(props, { emit }) {
    // 获取规格查询对象
    const pathMap = createPathMap(props.skus);
    // 点击规格,切换选中状态
    const updateSelect = (value, item) => {
      // 判断是否禁用 禁用则终止程序
      if (value.disabled) {
        return;
      }
      // 点击已经选中的则取消选中
      if (value.select) {
        value.select = false;
      } else {
        // 排他  给一个规格添加样式前先清除其他规格的样式
        item.values.forEach((item) => (item.select = false));
        // 给选中的规格添加选中状态
        value.select = true;
      }
      // 调用方法添加禁用状态
      updataDisabled(props.specs, pathMap);

      sendDataToParent(props.specs, props.skus, pathMap, emit);
    };
    // 调用方法添加禁用状态
    updataDisabled(props.specs, pathMap);
    // 默认选中效果
    setDefaultSelected(props.specs, props.skuId, props.skus);
    return {
      updateSelect,
      pathMap,
    };
  },
};
// 添加选中状态
// 创建规格查询对象
function createPathMap(skus) {
  const pathMap = {};
  skus.forEach((sku) => {
    // 判斷商品规格是否有库存,
    if (sku.inventory > 0) {
      // 有库存
      const names = sku.specs.map((item) => item.valueName);
      // 保存完整规格长度
      const max = names.length;
      const sets = bwPowerSet(names).filter((item) => item.length > 0);
      sets.forEach((set) => {
        const key = set.join("_");
        // 存入查询规格对象中
        // 判断是否已经有值
        if (!(key in pathMap)) {
          // 判断是否等于完整规格长度
          if (set.length === max) {
            // 等于则添加id
            pathMap[key] = sku.id;
          } else {
            // 不等于则添加null
            pathMap[key] = null;
          }
        }
      });
    }
  });
  return pathMap;
}
// 添加禁用状态
function updataDisabled(specs, pathMap) {
  specs.forEach((spec, index) => {
    // 获取用户选择的规格对象
    const selected = getSelected(specs);
    // 获取具体规格对象
    spec.values.forEach((value) => {
      // 判断具体规格对象是否已经选中，如果选中则已经存在在select中,
      if (value.select) return;
      // 如果没有选中则添加到用户选择的规格对象中,与用户选择的规格组合,然后判断规格对象中是否有此规格
      selected[index] = value.name;
      const key = selected.filter((item) => item).join("_");
      // 判断如果规格存在与规格对象中,则不禁用,否则则禁用
      value.disabled = !(key in pathMap);
    });
  });
}
// 获取用户选择的规格
function getSelected(specs) {
  // 保存用户选择的规格
  const result = [];
  specs.forEach((spec, index) => {
    // console.log(spec);
    // 每个规格选项只能选择一个,所以用find查找
    const select = spec.values.find((value) => value.select);
    // 判断选中则添加name,没有选中则添加undefined
    if (select) {
      result[index] = select.name;
    } else {
      result[index] = undefined;
    }
  });
  return result;
}
// 设置默认选中效果
function setDefaultSelected(specs, sukId, suks) {
  if (!sukId) return;
  const target = suks.find((suk) => suk.id === sukId);
  const names = target.specs.map((spec) => spec.valueName);
  specs.forEach((spec) => {
    spec.values.forEach((value) => {
      if (names.includes(value.name)) {
        value.select = true;
      }
    });
  });
}
// 将用户选择的规格数据传入到父组件;
function sendDataToParent(specs, skus, pathMap, emit) {
  // 获取用户选择的规格
  const selected = getSelected(specs).filter((item) => item);
  // 判断规格是否完整,完整才需要传出到父组件
  if (selected.length === specs.length) {
    // 规格组件完整, 获取规格id
    const skuId = pathMap[selected.join("_")];
    const result = skus.find((sku) => sku.id === skuId);
    emit("onSpecChanged", {
      skuId,
      price: result.price,
      oldPrice: result.oldPrice,
      inventory: result.inventory,
      attrsText: result.specs
        .map((spec) => `${spec.name}:${spec.valueName}`)
        .join(" "),
    });
  }
}
</script>
<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;
  margin-bottom: 10px;
  &.selected {
    border-color: @xtxColor;
  }
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}
.goods-sku {
  padding-left: 10px;
  padding-top: 20px;
  dl {
    display: flex;
    padding-bottom: 5px;
    align-items: center;
    dt {
      width: 50px;
      color: #999;
    }
    dd {
      flex: 1;
      color: #666;
      > img {
        width: 50px;
        height: 50px;
        .sku-state-mixin ();
      }
      > span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>
